package by.alex.dzeshko.lastfmsimple.http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import by.alex.dzeshko.lastfmsimple.app.ContextHolder;

public class HttpManager {

	private static HttpManager instance;
	
	private DefaultHttpClient client;
	
	private static final int SO_TIMEOUT = 20000;

	private static final String UTF_8 = "UTF-8";

	private static final String LOG_TAG = "HttpManager";
	
	private Context mContext;
	
	private HttpManager() {
		mContext = ContextHolder.getInstance().getContext();
		HttpParams params = new BasicHttpParams();
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, UTF_8);
		params.setBooleanParameter("http.protocol.expect-continue", false);
		HttpConnectionParams.setConnectionTimeout(params, SO_TIMEOUT);
		HttpConnectionParams.setSoTimeout(params, SO_TIMEOUT);
		SchemeRegistry registry = new SchemeRegistry();
		registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
		sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		registry.register(new Scheme("https", sslSocketFactory, 443));
		ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
		client = new DefaultHttpClient(manager, params);
	}

	public static HttpManager getInstance(){
		if(instance==null){
			instance = new HttpManager();
		}
		return instance;
	}
	
	public String loadAsString(String url) throws IOException {
		Log.d(LOG_TAG, "query: "+url);
		return getStringResponse(new HttpGet(url));
	}
	
	public JSONObject loadAsJSONObject(String url) throws IOException, JSONException {
		return new JSONObject(loadAsString(url));
	}
	
	public JSONArray loadAsJSONArray(String url) throws IOException, JSONException {
		return new JSONArray(loadAsString(url));
	}
	
	
	public Bitmap loadBitmap(String url) throws ClientProtocolException, IOException {
		InputStream content = null;
		Bitmap bitmap = null;
		HttpClient client = new DefaultHttpClient();
		HttpResponse response;
		response = client.execute(new HttpGet(url));
		BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(response.getEntity());
        content = bufHttpEntity.getContent();
        int l = (int)bufHttpEntity.getContentLength();
        if(content!=null)
        	bitmap = BitmapFactory.decodeStream(content);
        else Log.e("HttpManager.loadBitmap","inp stream = null");
		content.close();
		if(bitmap!=null)
		return bitmap;
		else throw new IOException("Bitmap is null at HttpManager.");
		
	}
	
	public String postRequest(String url, ArrayList<BasicNameValuePair> data) throws ClientProtocolException, IOException{
		HttpPost httpPost = new HttpPost(url);
		for(BasicNameValuePair p : data){
			Log.d(p.getName(), p.getValue());
		}
		UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(data, HTTP.UTF_8);
		httpPost.setEntity(postEntity);
		return getStringResponse(httpPost);
	}

	public String postRequest(String url) throws ClientProtocolException, IOException{
		HttpPost httpPost = new HttpPost(url);
		return getStringResponse(httpPost);
	}
	
	public String deleteRequest (String url) throws ClientProtocolException, IOException{
		HttpDelete httpDel = new HttpDelete(url);
		return getStringResponse(httpDel);
	}

	private String getStringResponse(HttpRequestBase httpRequest) throws IOException,	ClientProtocolException {
		InputStream content = null;
		BufferedReader reader = null;
		HttpResponse response;
		String value = null;
		try {
			response = client.execute(httpRequest);
			HttpEntity resEntity = response.getEntity();
			content = resEntity.getContent();
			reader = new BufferedReader(new InputStreamReader(content), 8192);
			StringBuilder sb = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line).append(System.getProperty("line.separator"));
			}
			value = sb.toString();
			content.close();
		} catch (ClientProtocolException e) {
			throw e;
		} catch (IOException e) {
			throw e;
		} finally {
			if(content!=null){
				try {
					content.close();
				} catch (IOException e) {
					// ignored because already closed
					e.printStackTrace();
				}
			}
			if(reader!=null){
				try {
					reader.close();
				} catch (IOException e) {
					// ignored because already closed
					e.printStackTrace();
				}
			}
		}
		
		Log.d("RESPONSE", value);
		return value;
	}
	
	public static boolean isNetworkAvailable() {
		Context ctx = ContextHolder.getInstance().getContext();
	    ConnectivityManager connectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
	    NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
	    return activeNetworkInfo != null;
	}
	
}